#include "Row.h"
#include "util.h"
#include <rapidjson/document.h>

using namespace std;
using namespace rapidjson;

Row::Row() : Row("", { }) { }

Row::Row(std::string rowKey, std::initializer_list<Cell> cells = {}) : Key(std::move(rowKey)), Cells(cells) { }

std::string Row::ToString() const
{
    auto dom = Document();
    dom.SetObject();
    auto rowShell = Document();
    rowShell.SetArray();
    auto row = Document();
    row.SetObject();
    row.AddMember("key", Document().SetString(Base64Encode(Key).c_str(), dom.GetAllocator()), dom.GetAllocator());
    auto cells = Document();
    cells.SetArray();
    for(const auto& i : Cells)
    {
        auto cell = Document();
        cell.SetObject();
        cell.AddMember("column", Document().SetString(Base64Encode(i.column).c_str(), dom.GetAllocator()), dom.GetAllocator());
        cell.AddMember("$", Document().SetString(Base64Encode(i.value).c_str(), dom.GetAllocator()), dom.GetAllocator());
        if (i.withTimestamp)
            cell.AddMember("timestamp", i.timestamp, dom.GetAllocator());
        cells.PushBack(cell, dom.GetAllocator());
    }
    row.AddMember("Cell", cells, dom.GetAllocator());
    rowShell.PushBack(row, dom.GetAllocator());
    dom.AddMember("Row", rowShell, dom.GetAllocator());
    return GetJsonString(dom);
}

bool Row::FromString(const string &json)
{
    auto dom = Document();
    dom.Parse(json.c_str());
    if(dom.HasParseError())
        return false;
    if(!dom.HasMember("Row"))
        return false;
    if(!dom["Row"].IsArray())
        return false;
    if(!dom["Row"].GetArray().Begin()->IsObject())
        return false;
    auto row = dom["Row"].GetArray().Begin()->GetObject();
    if(!row.HasMember("key"))
        return false;
    if(!row.HasMember("Cell"))
        return false;
    if(!row["key"].IsString())
        return false;
    if(!row["Cell"].IsArray())
        return false;
    Key = Base64Decode(row["key"].GetString());
    auto cells = row["Cell"].GetArray();
    Cells.clear();
    for (auto i = cells.Begin(); i != cells.End(); i++)
    {
        if(!i->HasMember("column"))
            return false;
        if(!i->HasMember("$"))
            return false;
        if(!(*i)["column"].IsString())
            return false;
        if(!(*i)["$"].IsString())
            return false;
        auto key = Base64Decode((*i)["column"].GetString());
        auto value = Base64Decode((*i)["$"].GetString());
        if(i->HasMember("timestamp"))
        {
            if (!(*i)["timestamp"].IsUint64())
                return false;
            uint64_t timestamp = (*i)["timestamp"].GetUint64();
            Cells.emplace_back(Cell(key, value, timestamp));
        }
    }
    return true;
}